package pl.edu.pw.elka.tinyrepo.dataserver.server;

 //TODO nietestowane!

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;

import pl.edu.pw.elka.tinyrepo.common.HTTPHeaderType;
import pl.edu.pw.elka.tinyrepo.common.RequestHandler;
import pl.edu.pw.elka.tinyrepo.common.Response;
import pl.edu.pw.elka.tinyrepo.common.StatusCode;
import pl.edu.pw.elka.tinyrepo.common.exceptions.ContentAlreadyExistException;
import pl.edu.pw.elka.tinyrepo.common.exceptions.WrongPathException;
import pl.edu.pw.elka.tinyrepo.gate.server.GateFacade;

class PUTRequestHandler extends DataServerRequestHandler {
   /** Plik do ktorego bedziemy zapisywac dane. */
   private File outputFile;
   /** Rozmiar bufora przy odczytywaniu danych. */
   static final int BUFFER_SIZE = 256;
   
   public PUTRequestHandler(File dataCatalog, GateFacade gate) {
      this.dataCatalog = dataCatalog;
      this.gate = gate;
   }
   
   @Override
   public RequestHandler copy() {
      return new PUTRequestHandler(dataCatalog, gate);
   }

   @Override
   public void run() {
      FileOutputStream out = null;
      InputStream in = null;
      OutputStream socketOut = null;
      Boolean repoChanged = false;
      String path = request.getPath();
      try {
         in = incomming.getInputStream();
         socketOut = incomming.getOutputStream();
         Integer id = createUniqueID(); // FIXME potencjalne nadpisywanie danych w wyniku overflow dla duzej liczby plikow
         
         // wydobywanie rozmiaru
         Long size = 0L;
         try {
            size = Long.parseLong(request.getHeader(HTTPHeaderType.CONTENT_LENGTH));
         
         }
         catch (Exception e) {
            throw new IllegalArgumentException("BAD REQUEST");
         }
         
         // sprobuj zajac miejsce w deskryptorze pliku
         if(!gate.putFile(path, id, size, incomming.getLocalPort()))
               throw new IllegalArgumentException("Wrong path"); // albo inny DS nas ubiegl, albo klient podal zla sciezke do repozytorium
         repoChanged = true;
         
         // sprawdzenie czy plik da sie zapisac
         outputFile = new File(dataCatalog, id.toString());
         System.out.println("New file: " + path + " with id: "+outputFile.getName());
         if(outputFile.exists())
            throw new ContentAlreadyExistException(getRequest().getPath()); // plik o podanej nazwie istnieje - klient probuje drugi raz wyslac ten sam plik
         
         // wyglada, ze wszystko ok, wysylamy OK do klienta
         // istotna jest kolejnosc: najpierw odpowiedz, ze ok, dopiero potem 
         // odbieranie danych.
         // bo klient po wyslaniu request header oczekuje na odpowiedz,
         // dopiero po tej odpowiedzi klient reaguje wysylaniem danych
         
         Response r = new Response(StatusCode.OK);
         r.write(incomming.getOutputStream()); // odpowiadamy ze ok
         System.out.println("Sent response: \n"+r);
         
         // czytanie pliku
         outputFile.createNewFile(); // utworzenie nowego pliku o podanej nazwie
         out = new FileOutputStream(outputFile);
         DataServerRequestHandler.writeBytes(out, in, BUFFER_SIZE);
         
         // TODO na razie bez dodatkowych naglowkow
         
      } 
      catch (WrongPathException e) { // sciezka dostepu nie istnieje
         e.printStackTrace();
         Response r = new Response(StatusCode.NOT_FOUND);
         r.write(socketOut);
      } 
      catch (ContentAlreadyExistException e) { // plik juz istnieje
         e.printStackTrace();
         Response r = new Response(StatusCode.CONFLICT);
         r.write(socketOut);
         if(repoChanged)
            try {
               gate.dropFile(path); // napraw repo
            } catch (RemoteException e1) {
               e1.printStackTrace();
            } 
      } 
      catch (IllegalArgumentException e) { // zle sformulowane zapytanie
         e.printStackTrace();
         Response r = new Response(StatusCode.BAD_REQUEST);
         r.write(socketOut);
      }
      catch (Exception e) { // pozostale bledy - konczy sie zazwyczaj na serwerze - zakoncz dzialanie
         e.printStackTrace();
         if(repoChanged)
            try {
               gate.dropFile(path); // napraw repo
            } catch (RemoteException e1) {
               e1.printStackTrace();
            } 
      } 
      finally {
         try {
            if(out != null)
               out.close();
            
            // socket zamykany w klasach DAVServer.java
         } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
   }
   
   
   /**
    * Zwraca nowy unikalny id dla katalogu dataServera. Nowy unikalny id 
    * jest kolejna (+1) liczba po najwiekszym uid dostepnym w katalogu serwera.
    * 
    * @return nowy unikalny id
    * @throws WrongPathException 
    */
   private Integer createUniqueID() throws Exception { // TODO miejsce potencjalnej optymalizacji
      if(!dataCatalog.isDirectory())
         throw new Exception("Wrong data directory");
      String[] files = dataCatalog.list();
      Integer max = 0;
      for(String f: files) { 
         Integer i = null;
         try {
            i = Integer.parseInt(f);
         } catch (NumberFormatException e) {
        	 continue;
            //System.err.println("DS: found some junk: "+f); // FIXME mozna by usuwac, ale poki co to nie
         }
         if(i > max)
            max = i;
      }
      return new Integer(max+1); // FIXME moze dojsc do overflow z biegiem czasu, na razie zaklada sie ze system jest dla malej liczby plikow
   }
   

}
